package org.base.sys.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.base.Pkg;
import org.base.common.annotation.RequiredPerm;
import org.base.common.service.impl.ServiceImpl;
import org.base.common.util.SpringContextUtils;
import org.base.sys.dao.SysUrlPermissionMapper;
import org.base.sys.pojo.SysUrlPermission;
import org.base.sys.query.SysUrlPermissionQuery;
import org.base.sys.service.SysUrlPermissionService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 路径权限 服务实现类
 * </p>
 *
 * @author AutoGenerator
 * @since 2020-07-29
 */
@Service
@Slf4j
@AllArgsConstructor
public class SysUrlPermissionServiceImpl extends ServiceImpl<SysUrlPermissionMapper, SysUrlPermission, SysUrlPermissionQuery> implements SysUrlPermissionService {

    @Override
    @Transactional
    public boolean syncPerm() {
        RequestMappingHandlerMapping mapping = SpringContextUtils.getBean("requestMappingHandlerMapping", RequestMappingHandlerMapping.class);
        final Map<RequestMappingInfo, HandlerMethod> handlerMethods = mapping.getHandlerMethods();
        final Set<RequestMappingInfo> requestMappingInfos = handlerMethods.keySet();
        SysUrlPermission permission = null;
        List<SysUrlPermission> perms = new ArrayList<>();
        final String basePkg = Pkg.class.getPackage().getName();
        if (requestMappingInfos != null && requestMappingInfos.size() > 0) {
            for (RequestMappingInfo requestMappingInfo : requestMappingInfos) {
                final HandlerMethod handlerMethod = handlerMethods.get(requestMappingInfo);
                final Method method = handlerMethod.getMethod();
                final RequiredPerm requiredPerm = method.getAnnotation(RequiredPerm.class);
                final Class<?> declaringClass = method.getDeclaringClass();
                final Package pkg = declaringClass.getPackage();
                final String pkgName = pkg.getName();
                if (pkgName.startsWith(basePkg)) {
                    final Set<String> patterns = requestMappingInfo.getPatternsCondition().getPatterns();
                    if (patterns != null && patterns.size() > 0) {
                        permission = new SysUrlPermission();
                        permission.setPath(StringUtils.join(patterns, ","));
                        permission.setClassName(declaringClass.getSimpleName());
                        if (requiredPerm != null) {
                            permission.setPerm(requiredPerm.value());
                            permission.setEditable(requiredPerm.editable());
                        } else {
                            permission.setEditable(true);
                        }
                        perms.add(permission);
                    }
                }
            }
        }
        if (perms.size() > 0) {
            final Page<SysUrlPermission> page = new Page<>();
            page.setSize(10000);
            page.setCurrent(1L);
            page(page);
            final List<SysUrlPermission> records = page.getRecords();
            if (CollectionUtils.isNotEmpty(records)) {
                final Set<String> permSet = records.stream().map(SysUrlPermission::getPath).collect(Collectors.toSet());
                perms = perms.stream().filter(e -> !permSet.contains(e.getPath())).collect(Collectors.toList());
            }
            if (perms.size() > 0) {
                saveBatch(perms);
            }
        }
        return true;
    }

    @Override
    public boolean saveOrUpdate(SysUrlPermission entity) {
        final Long id = entity.getId();
        if (id != null) {
            final SysUrlPermission urlPermission = getById(id);
            urlPermission.setPerm(entity.getPerm());
            super.saveOrUpdate(urlPermission);
        }
        return true;
    }

    @Override
    public String getPathPerm(String url) {
        final SysUrlPermission urlPermission = lambdaQuery().eq(SysUrlPermission::getPath, url).one();
        if (urlPermission != null) {
            return urlPermission.getPerm();
        }
        return null;
    }
}
